#include "iomanager.h"
#include "marco.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <string.h>
#include <unistd.h>

//根据事件类型，获取到对应的结构体
IOManager::FdContext::EventContext& IOManager::FdContext::getContext(IOManager::Event event) {
    switch(event) {
        case IOManager::READ:
            return read;
        case IOManager::WRITE:
            return write;
        default:
            SYLAR_ASSERT2(false, "getContext");
    }
    throw std::invalid_argument("getContext invalid event");
}

//重置事件
void IOManager::FdContext::resetContext(EventContext& ctx) {
    ctx.scheduler = nullptr;
    ctx.fiber.reset();
    ctx.cb = nullptr;
}

//触发事件
void IOManager::FdContext::triggerEvent(IOManager::Event event) {
    //SYLAR_LOG_INFO(g_logger) << "fd=" << fd
    //    << " triggerEvent event=" << event
    //    << " events=" << events;
    SYLAR_ASSERT(events & event);
    //if(SYLAR_UNLIKELY(!(event & event))) {
    //    return;
    //}
    events = (Event)(events & ~event); //删除event事件
    EventContext& ctx = getContext(event);
    if(ctx.cb) { //有回调函数
        ctx.scheduler->schedule(&ctx.cb);
    } else { //用协程方式
        ctx.scheduler->schedule(&ctx.fiber);
    }
    ctx.scheduler = nullptr; //置为nullptr
    return;
}

//有参构造
IOManager::IOManager(size_t threads, bool use_caller, const std::string& name)
    :Scheduler(threads, use_caller, name) {
    m_epfd = epoll_create(5000); //创建监听文件描述符
    SYLAR_ASSERT(m_epfd > 0);

    int rt = pipe(m_tickleFds); //创建管道
    SYLAR_ASSERT(!rt);

    epoll_event event; //创建事件
    memset(&event, 0, sizeof(epoll_event));
    event.events = EPOLLIN | EPOLLET; 
    event.data.fd = m_tickleFds[0]; //存储新创建的管道的文件描述符 m_tickleFds[0] 用于读取

    rt = fcntl(m_tickleFds[0], F_SETFL, O_NONBLOCK); //设置为非阻塞
    SYLAR_ASSERT(!rt);

    rt = epoll_ctl(m_epfd, EPOLL_CTL_ADD, m_tickleFds[0], &event); //添加到事件数组中
    SYLAR_ASSERT(!rt);

    contextResize(32);

    start();
}

IOManager::~IOManager() {
    stop();
    close(m_epfd);
    close(m_tickleFds[0]);
    close(m_tickleFds[1]);

    for(size_t i = 0; i < m_fdContexts.size(); ++i) {
        if(m_fdContexts[i]) {//循环释放事件
            delete m_fdContexts[i];
        }
    }
}

void IOManager::contextResize(size_t size) {
    m_fdContexts.resize(size);

    for(size_t i = 0; i < m_fdContexts.size(); ++i) {
        if(!m_fdContexts[i]) { //为每一个创建一个实例
            m_fdContexts[i] = new FdContext;
            m_fdContexts[i]->fd = i;
        }
    }
}

//添加事件
int IOManager::addEvent(int fd, Event event, std::function<void()> cb) {
    FdContext* fd_ctx = nullptr;
    RWMutexType::readLock lock(m_mutex);
    if((int)m_fdContexts.size() > fd) { //如果内存空间比fd大，说明数组内存一个分配好
        fd_ctx = m_fdContexts[fd];
        lock.unlock();
    } else {
        lock.unlock();
        RWMutexType::writeLock lock2(m_mutex); 
        contextResize(fd * 1.5);    //否则重新分配内存
        fd_ctx = m_fdContexts[fd]; 
    }

    FdContext::MutexType::Lock lock2(fd_ctx->mutex);
    if(SYLAR_UNLIKELY(fd_ctx->events & event)) { //如果要添加的event已经存在，那就是存在问题
        std::cout << "addEvent assert fd=" << fd
                    << " event=" << (EPOLL_EVENTS)event
                    << " fd_ctx.event=" << (EPOLL_EVENTS)fd_ctx->events << std::endl;
        SYLAR_ASSERT(!(fd_ctx->events & event));
    }

    int op = fd_ctx->events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; //添加到列表中的事件类型
    epoll_event epevent; //结构体
    epevent.events = EPOLLET | fd_ctx->events | event;
    epevent.data.ptr = fd_ctx; //存放到结构体中的数据区

    int rt = epoll_ctl(m_epfd, op, fd, &epevent); //添加到监听列表中
    if(rt) {
        std::cout << "epoll_ctl(" << m_epfd << ", "
            << op << ", " << fd << ", " << epevent.events << "):"
            << rt << " (" << errno << ") (" << strerror(errno) << ") fd_ctx->events="
            << (EPOLL_EVENTS)fd_ctx->events << std::endl;
        return -1;
    }

    ++m_pendingEventCount; //事件数量加1
    fd_ctx->events = (Event)(fd_ctx->events | event); //设置当前事件
    FdContext::EventContext& event_ctx = fd_ctx->getContext(event);
    SYLAR_ASSERT(!event_ctx.scheduler
                && !event_ctx.fiber
                && !event_ctx.cb);

    event_ctx.scheduler = Scheduler::GetThis(); //设置当前调度器
    if(cb) {    //如果是回调函数方式
        event_ctx.cb.swap(cb); 
    } else { //不是回调函数方式
        event_ctx.fiber = Fiber::GetThis(); //设置协程
        SYLAR_ASSERT2(event_ctx.fiber->getState() == Fiber::EXEC //已经结束的
                      ,"state=" << event_ctx.fiber->getState());
    }
    return 0; //表示成功
}

//删除事件
bool IOManager::delEvent(int fd, Event event) {
    RWMutexType::readLock lock(m_mutex);
    if((int)m_fdContexts.size() <= fd) { //如果内存大小小于fd，证明句柄不存在
        return false;
    }
    FdContext* fd_ctx = m_fdContexts[fd]; //存在就获取值
    lock.unlock();

    FdContext::MutexType::Lock lock2(fd_ctx->mutex);
    if(SYLAR_UNLIKELY(!(fd_ctx->events & event))) { //判断事件是否存在，不存在也不用删除
        return false;
    }

    Event new_events = (Event)(fd_ctx->events & ~event); //清楚event事件
    int op = new_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; //new_events为非0就修改，为0就删除
    epoll_event epevent;
    epevent.events = EPOLLET | new_events;
    epevent.data.ptr = fd_ctx;

    int rt = epoll_ctl(m_epfd, op, fd, &epevent); //修改或者删除
    if(rt) {
        std::cout << "epoll_ctl(" << m_epfd << ", "
            << op << ", " << fd << ", " << (EPOLL_EVENTS)epevent.events << "):"
            << rt << " (" << errno << ") (" << strerror(errno) << ")" << std::endl;
        return false;
    }

    --m_pendingEventCount; //事件数量减1
    fd_ctx->events = new_events; //设置当前事件
    FdContext::EventContext& event_ctx = fd_ctx->getContext(event); //获取结构体EventContext
    fd_ctx->resetContext(event_ctx); //重置EventContext结构体
    return true; //删除或修改成功
}

//取消事件
bool IOManager::cancelEvent(int fd, Event event) {
    RWMutexType::readLock lock(m_mutex);
    if((int)m_fdContexts.size() <= fd) {
        return false;
    }
    FdContext* fd_ctx = m_fdContexts[fd];
    lock.unlock();

    FdContext::MutexType::Lock lock2(fd_ctx->mutex);
    if(SYLAR_UNLIKELY(!(fd_ctx->events & event))) {
        return false;
    }

    Event new_events = (Event)(fd_ctx->events & ~event);
    int op = new_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
    epoll_event epevent;
    epevent.events = EPOLLET | new_events;
    epevent.data.ptr = fd_ctx;

    int rt = epoll_ctl(m_epfd, op, fd, &epevent);
    if(rt) {
        std::cout << "epoll_ctl(" << m_epfd << ", "
            << op << ", " << fd << ", " << (EPOLL_EVENTS)epevent.events << "):"
            << rt << " (" << errno << ") (" << strerror(errno) << ")" << std::endl;
        return false;
    }

    fd_ctx->triggerEvent(event);
    --m_pendingEventCount;
    return true;
}

bool IOManager::cancelAll(int fd) {
    RWMutexType::readLock lock(m_mutex);
    if((int)m_fdContexts.size() <= fd) {
        return false;
    }
    FdContext* fd_ctx = m_fdContexts[fd];
    lock.unlock();

    FdContext::MutexType::Lock lock2(fd_ctx->mutex);
    if(!fd_ctx->events) { //如果没有事件
        return false;
    }

    int op = EPOLL_CTL_DEL;
    epoll_event epevent;
    epevent.events = 0;
    epevent.data.ptr = fd_ctx;

    int rt = epoll_ctl(m_epfd, op, fd, &epevent);
    if(rt) {
        std::cout << "epoll_ctl(" << m_epfd << ", "
            << op << ", " << fd << ", " << (EPOLL_EVENTS)epevent.events << "):"
            << rt << " (" << errno << ") (" << strerror(errno) << ")" << std::endl;
        return false;
    }

    if(fd_ctx->events & READ) {
        fd_ctx->triggerEvent(READ);
        --m_pendingEventCount;
    }
    if(fd_ctx->events & WRITE) {
        fd_ctx->triggerEvent(WRITE);
        --m_pendingEventCount;
    }

    SYLAR_ASSERT(fd_ctx->events == 0);
    return true;
}

//获取到IOManger
IOManager* IOManager::GetThis() {
    return dynamic_cast<IOManager*>(Scheduler::GetThis());
}

//
bool IOManager::stopping(uint64_t& timeout) {
    return false;
    timeout = getNextTimer();
    return timeout == ~0ull
        && m_pendingEventCount == 0
        && Scheduler::stopping();
}

//有事件就写 
void IOManager::tickle() {
    if(!hasIdleThreads()) {
        return;
    }
    int rt = write(m_tickleFds[1], "T", 1); //写数据
    SYLAR_ASSERT(rt == 1);
}

//这个stopping给scheduler用
bool IOManager::stopping() {
    return Scheduler::stopping() && m_pendingEventCount==0;

    // timeout = getNextTimer();
    // return timeout == ~0ull
    //     && m_pendingEventCount == 0
    //     && Scheduler::stopping();
}

void IOManager::idle() {
    std::cout << "idle" << std::endl;
    const uint64_t MAX_EVNETS = 256;
    epoll_event* events = new epoll_event[MAX_EVNETS](); //创建epoll_event事件
    std::shared_ptr<epoll_event> shared_events(events, [](epoll_event* ptr){
        delete[] ptr; //这样子做可以支持析构的
    });

    while(true) {
        uint64_t next_timeout = 0;
        if(SYLAR_UNLIKELY(stopping(next_timeout))) { //如果是停止的
            std::cout << "name=" << getName()
                                     << " idle stopping exit" << std::endl;
            break;
        }

        int rt = 0;
        do {
            static const int MAX_TIMEOUT = 3000; //设置的超时时间
            if(next_timeout != ~0ull) { //判断是否有超时时间
                next_timeout = (int)next_timeout > MAX_TIMEOUT
                                ? MAX_TIMEOUT : next_timeout;
            } else {
                next_timeout = MAX_TIMEOUT;
            }
            rt = epoll_wait(m_epfd, events, MAX_EVNETS, (int)next_timeout); //查看是否有事件被触发
            if(rt < 0 && errno == EINTR) { //有错或者没有事件
            } else {
                break;
            }
        } while(true);

        std::vector<std::function<void()> > cbs; //定时器的回调函数容器
        listExpiredCb(cbs); //返回对应的回调函数
        if(!cbs.empty()) {
            //SYLAR_LOG_DEBUG(g_logger) << "on timer cbs.size=" << cbs.size();
            schedule(cbs.begin(), cbs.end()); //存在就全部用作协程处理任务
            cbs.clear();
        }

        //if(SYLAR_UNLIKELY(rt == MAX_EVNETS)) {
        //    SYLAR_LOG_INFO(g_logger) << "epoll wait events=" << rt;
        //}

        for(int i = 0; i < rt; ++i) { //处理触发的事件
            epoll_event& event = events[i];
            if(event.data.fd == m_tickleFds[0]) { //句柄为0号，表示需要读取消息
                uint8_t dummy[256];
                while(read(m_tickleFds[0], dummy, sizeof(dummy)) > 0); //读取数据
                continue;
            }

            FdContext* fd_ctx = (FdContext*)event.data.ptr; //提取结构体
            FdContext::MutexType::Lock lock(fd_ctx->mutex);
            if(event.events & (EPOLLERR | EPOLLHUP)) { //错误或者是中断
                event.events |= (EPOLLIN | EPOLLOUT) & fd_ctx->events; //修改成读和写事件
            }
            int real_events = NONE;
            if(event.events & EPOLLIN) { //读事件
                real_events |= READ;
            }
            if(event.events & EPOLLOUT) { //写事件
                real_events |= WRITE;
            }

            if((fd_ctx->events & real_events) == NONE) { //没有事件
                continue;   //跳过
            }
            //一个结构体存在多个事件处理，如EPOLLIN和EPOLLOUT 触发哪个就处理哪个
            int left_events = (fd_ctx->events & ~real_events); //把触发的事件去除
            int op = left_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
            event.events = EPOLLET | left_events; //把事件设置为剩余的事件

            int rt2 = epoll_ctl(m_epfd, op, fd_ctx->fd, &event); //并且重新添加进入事件数组中
            if(rt2) {
                std::cout << "epoll_ctl(" << m_epfd << ", "
                    << op << ", " << fd_ctx->fd << ", " << (EPOLL_EVENTS)event.events << "):"
                    << rt2 << " (" << errno << ") (" << strerror(errno) << ")" << std::endl;
                continue;
            }

            //SYLAR_LOG_INFO(g_logger) << " fd=" << fd_ctx->fd << " events=" << fd_ctx->events
            //                         << " real_events=" << real_events;
            if(real_events & READ) { //有读事件
                fd_ctx->triggerEvent(READ); //触发
                --m_pendingEventCount;
            }
            if(real_events & WRITE) {
                fd_ctx->triggerEvent(WRITE);
                --m_pendingEventCount;
            }
        }

        //让出idle的执行权
        Fiber::ptr cur = Fiber::GetThis();
        auto raw_ptr = cur.get();
        cur.reset();
        raw_ptr->swapOut(); //换到主协程
    }
}

void IOManager::onTimerInsertedAtFront() {
    tickle();
}

